#include "Log.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include "InetArr.hpp"
#include <functional>
#include "Log.hpp"
#include "Protocol.hpp"

using namespace LogModule;
int main(int argc, char *argv[])
{
    LOG_FILE();
    // ./udp_server 127.0.0.1 8080
    std::string ip = "47.98.139.142";
    uint16_t port = 8080;
    if (argc == 3)
    {
        ip = argv[1];
        port = ::atoi(argv[2]);
    }
    else if (argc > 3 || argc == 2)
    {
        std::cout << "Usage ./client_server 47.98.139.142 8080" << std::endl;
        return 1;
    }

    // socket connect
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        LOG(LogLevel::ERROR) << "socket failed";
    }
    LOG(LogLevel::DEBUG) << "socket success";

    InetAddr inet(port, ip);

    int n = connect(sockfd, inet.NetAddr(), inet.NetAddrLen());
    if (n == -1)
    {
        LOG(LogLevel::ERROR) << "connect failed";
        DIE(CONNECT_ERROR);
    }
    LOG(LogLevel::DEBUG) << "connect success";

    std::string package;
    std::cout << "0 结果正常 1除零错误 2未知操作" << std::endl;
    while (true)
    {
        int x, y;
        char oper;
        std::cout << "Please X#";
        std::cin >> x;
        std::cout << "Please Y#";
        std::cin >> y;
        std::cout << "Please oper#";
        std::cin >> oper;

        Request req(x, y, oper);
        std::string s;
        req.Serialize(s);
        Encode(s);
        ssize_t n = ::send(sockfd, s.c_str(), s.size(), 0);
        if (n == -1)
        {
            LOG(LogLevel::ERROR) << "send failed";
            exit(1);
        }
        LOG(LogLevel::DEBUG) << s;

        char buffer[1024];
        n = ::recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n == -1)
        {
            LOG(LogLevel::ERROR) << "send failed";
            exit(1);
        }
        buffer[n] = 0;
        LOG(LogLevel::DEBUG) << buffer;
        package += buffer;

        std::string content;
        if (!Decode(package, &content))
            continue;
        Response res;
        res.Deserialize(content);
        std::cout << res.Result() << " (" << res.Code() << ")" << std::endl;
    }

    return 0;
}